package cn.zhqr.common.util.datetime;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by yantingjun on 2018/6/21.
 */
public class DateUtils {
    public static java.sql.Date toSqlDate(Date date){
        return new java.sql.Date(date.getTime());
    }
    public static Long getTodayStartSecond(){
        return getStartSecond(new Date());
    }
    public static Long getTodayEndSecond(){
        return getEndSecond(new Date());
    }
    public static Date yesterday(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_YEAR,-1);
        return calendar.getTime();
    }
    public static Date lastMonthFirstDay(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH,-1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    public static Date addDays(int days){
        return addDays(new Date(),days);
    }

    public static Date addDays(Date date,int days){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, days);
        return calendar.getTime();
    }

    public static Date addHours(int hours){
        return addHours(new Date(),hours);
    }

    public static Date addHours(Date date,int hours){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR, hours);
        return calendar.getTime();
    }
    public static Date addHours(long timestamp,int hours){
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp);
        calendar.add(Calendar.HOUR, hours);
        return calendar.getTime();
    }

    public static Long addMonth(long timestamp,int month){
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp*1000);
        calendar.add(Calendar.MONTH, month);
        return calendar.getTimeInMillis()/1000;
    }

    public static int getWeek(){
        Calendar today = Calendar.getInstance();
        return today.get(Calendar.WEEK_OF_MONTH);
    }
    public static Long getStartSecond(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);

        return calendar.getTimeInMillis()/1000;
    }

    /**
     * 计算两个时间戳相差的日期
     * @param t1
     * @param t2
     * @return
     */
    public static int diffDays(Long t1,Long t2){
        return (int)((t1-t2)/(24*3600*1000));
    }

    public static int diffDays(Date d1,Date d2){
        return diffDays(d1.getTime(),d2.getTime());
    }

    /**
     * 判断两个时间戳是否是同一天
     * @param t1       时间戳(毫秒)
     * @param t2       时间戳(毫秒)
     * @return
     */
    public static boolean isSameDay(Long t1,Long t2){
        return isSameDay(new Date(t1),new Date(t2));
    }
    public static boolean isSameDay(Date d1,Date d2){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(d1);
        int day1 = calendar.get(Calendar.DAY_OF_YEAR);

        calendar.setTime(d2);
        int day2 = calendar.get(Calendar.DAY_OF_YEAR);

        return day1==day2;
    }
    public static Long getEndSecond(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY,23);
        calendar.set(Calendar.MINUTE,59);
        calendar.set(Calendar.SECOND,59);

        return calendar.getTimeInMillis()/1000;
    }

    public static LocalDate getLastDayOfMonth(LocalDate localDate){
        return localDate.withDayOfMonth(localDate.lengthOfMonth());
    }

    public static boolean isLastDayOfMonth(LocalDate localDate){
        return localDate.isEqual(getLastDayOfMonth(localDate));
    }

    public static boolean isTodayLastDayOfMonth(){
        return isLastDayOfMonth(LocalDate.now());
    }

    public static Long getStartSecondOfMonth(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);

        return calendar.getTimeInMillis()/1000;
    }

    public static Long getEndSecondOfMonth(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.add(Calendar.SECOND,-1);

        return calendar.getTimeInMillis()/1000;
    }

    public static Long getStartSecondOfYear(Integer year){
        Calendar calendar = Calendar.getInstance();

        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);

        return calendar.getTimeInMillis()/1000;
    }

    public static Long getEndSecondOfYear(Integer year){
        Calendar calendar = Calendar.getInstance();

        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, 11);
        calendar.set(Calendar.DAY_OF_MONTH, 31);

        calendar.set(Calendar.HOUR_OF_DAY,23);
        calendar.set(Calendar.MINUTE,59);
        calendar.set(Calendar.SECOND,59);

        return calendar.getTimeInMillis()/1000;
    }

    public static Long nowSecond(){
        return System.currentTimeMillis()/1000;
    }

    public static Date getFirstDayOfMonth(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH,1);
        return calendar.getTime();
    }

    public static Date getFirstDayOfLastMonth(){
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH,-1);
        calendar.set(Calendar.DAY_OF_MONTH,1);
        return calendar.getTime();
    }

    public static int getDayOfYear(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);

        return calendar.get(Calendar.DAY_OF_YEAR);
    }

    public static int getYear(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        return calendar.get(Calendar.YEAR);
    }

    public static int getCurYear() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.YEAR);
    }


    public static int getMonth(Date time) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        return calendar.get(Calendar.MONTH);
    }

    public static int getDayOfYear(Long second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(second*1000));

        return calendar.get(Calendar.DAY_OF_YEAR);
    }

    public static String formatTimestamp(int timestamp){
        int hours = timestamp/3600;
        int minutes = timestamp/60 - hours*60 ;
        int seconds = timestamp % 60;

        StringBuilder res = new StringBuilder();
        if(hours>0){
            res.append(hours).append("小时");
        }
        if(minutes>0){
            res.append(minutes).append("分");
        }
        res.append(seconds).append("秒");
        return res.toString();
    }

    public static Date parseDate(String date,String format){
        try{
            return getDateFormat(format).parse(date);
        }catch (Exception e){
            return null;
        }
    }

    public static String formatDate(String format, Date date){
        if(date==null){
            date = new Date();
        }
        return getDateFormat(format).format(date);
    }

    public static String friendlyTime(long duration, boolean show_seconds) {
        long hours = duration/3600;
        long minutes = (duration - hours*3600)/60;
        long seconds = duration % 60;

        StringBuilder sb  = new StringBuilder();
        if(hours > 0) {
            sb.append(hours).append("小时");
        }
        if(minutes > 0) {
            sb.append(minutes).append("分钟");
        }
        if(show_seconds && seconds > 0) {
            sb.append(seconds).append("秒");
        }

        return sb.toString() ;
    }

    public static String formatUnixTime(Long unix_time){
        if(unix_time==null || unix_time<=0) return "";
        DateFormat format = getDateFormat("yyyy-MM-dd HH:mm:ss");
        return format.format(new Date(unix_time*1000));
    }


    private static final ThreadLocal<Map<String, DateFormat>> dateFormatters = ThreadLocal.withInitial(() -> new HashMap());


    /**
     * 根据格式参数获取当前线程独享的DateFormat
     * @param pattern
     * @return
     */
    public static DateFormat getDateFormat(String pattern) {
        Map<String, DateFormat> formatters = dateFormatters.get();
        DateFormat formatter = formatters.get(pattern);
        if (formatter == null) {
            formatter = new SimpleDateFormat(pattern);
            formatters.put(pattern, formatter);
        }
        return formatter;
    }

    /**
     * 模拟php microtime(true) 函数
     * @return
     */
    public static double microtime(){
        return System.currentTimeMillis()/1000.00;
    }

    /**
     * 查询day天前的时间
     * @return
     */
    public static Long getDaysAgoSecond(int day){
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DAY_OF_MONTH,-day);
        instance.set(Calendar.HOUR_OF_DAY,0);
        instance.set(Calendar.MINUTE,0);
        instance.set(Calendar.SECOND,0);

        return instance.getTimeInMillis()/1000;
    }

    public static Long getThreeMonthsAgo() {
        //三个月前的时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.MONTH,-3);
        instance.set(Calendar.HOUR_OF_DAY,0);
        instance.set(Calendar.MINUTE,0);
        instance.set(Calendar.SECOND,0);

        return instance.getTimeInMillis()/1000;
    }

    /**
     * 时间是否是3个月以前
     * @param time
     * @return
     */
    public static Boolean isThreeMonthsAgo(Long time) {
        if (time == null){
            return false;
        }
        //三个月前的时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.MONTH,-3);
        instance.add(Calendar.DAY_OF_MONTH,+1);
        instance.set(Calendar.HOUR_OF_DAY,0);
        instance.set(Calendar.MINUTE,0);
        instance.set(Calendar.SECOND,0);

        return instance.getTimeInMillis()/1000 > time;
    }

    /**
     * 获取计算后的年份
     * 获取当前年，新数据使用，进入今年第91天以后，当前年+1，便于数据库查询
     */
    public static int getYearAfterCalculation() {
        int year = getCurYear();

        //今年开始时间
        Long second = getStartSecondOfYear(year);

        //已迁移数据时间大于今年开始时间，说明今年已建立表
        if (second < getThreeMonthsAgo()+60){
            year = year + 1 ;
        }

        return year;
    }

    public static Long getStartSecondOfMonth(Integer year,Integer month){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR,year);
        calendar.set(Calendar.MONTH,month-1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);

        return calendar.getTimeInMillis()/1000;
    }

    public static Long getEndSecondOfMonth(Integer year,Integer month){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR,year);
        calendar.set(Calendar.MONTH,month);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.add(Calendar.SECOND,-1);

        return calendar.getTimeInMillis()/1000;
    }

    public static String formatUnixTime(Long unix_time,String str){
        if(unix_time==null || unix_time<=0) return "";
        DateFormat format = getDateFormat(str);
        return format.format(new Date(unix_time*1000));
    }

}
